package com.rslai.commons.ssh;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.io.*;

public class JschSSHResponse extends AbstractSSHResponse implements SSHResponse {
    private final Log log = LogFactory.getLog(getClass());

    ByteArrayOutputStream responseBOS = new ByteArrayOutputStream(); // 保存

    /**
     * 构造函数
     * @param sshConfig ssh配置信息
     * @param isConnect true：是connect请求， false：是cmd请求，需要先处理命令行再处理body内容
     */
    public JschSSHResponse(SSHConfig sshConfig, boolean isConnect) {
        this.sshConfig = sshConfig;
        this.isConnect = isConnect;
    }

    /**
     * 添加放回信息，从ssh输出流读入一组数据后添加一次
     * @param bytes
     * @param length
     */
    public void addResponse(byte[] bytes, int length) {
        // log.debug(new util().toAsciiString(bytes, length));
        responseBOS.write(bytes, 0, length);

        if (isEof(bytes, length)) {
            this.done = true;

            byte[] responseBytes = responseBOS.toByteArray();
            int cmdIndex = readCmd(responseBytes);
            int promptIndex = readPrompt(responseBytes);
            readBody(responseBytes, cmdIndex, promptIndex);
            responseBOS = null;
        }
    }

    /**
     * 读cmd信息
     * @param bytes
     * @return
     */
    private int readCmd(byte[] bytes) {
        if (this.isConnect) {
            return 0;
        } else {
            int length = bytes.length;
            for (int i = 0; i < length; i++) {
                if ((bytes[i] == 13) && ((i + 1) < length) && (bytes[i + 1] == 10)) { // 从0开始第一个 \r\n，之间的是cmd
                    cmd = util.byte2str(bytes, 0, i, this.sshConfig.getCharset()).replace(" \r", "");
                    return i + 2;
                }
            }
            return length;
        }
    }

    /**
     * 读cmd执行后返回信息
     * @param bytes
     * @param s
     * @param e
     */
    private void readBody(byte[] bytes, int s, int e) {
        if (s < e) {
            body = util.byte2str(bytes, s, e - s, this.sshConfig.getCharset());
        }
    }

    /**
     * 读命令提示行
     * @param bytes
     * @return
     */
    private int readPrompt(byte[] bytes) {
        for (int i=bytes.length-1; i>=0; i--) {
            if (((i-1)>=0) && (bytes[i-1]==10) && ((i-2)>=0) && (bytes[i-2]==13)) { // 从最后往前第一个 \r\n，之间的是提示行
                prompt = util.byte2str(bytes, i, bytes.length-i, this.sshConfig.getCharset());
                return i-2;
            }
        }
        return 0;
    }

    /**
     * 判断是否读到结尾
     * @param bytes
     * @param length
     * @return true: 已经读到结尾， false: 没有读到结尾
     */
    private boolean isEof(byte[] bytes, int length) {
        if (length >= 2) {
            byte lastChar_2 = bytes[length - 2];
            byte lastChar_1 = bytes[length - 1];

            // 有些命令执行后，会在最后一行输出一些特殊字符，比如：27 91 75（清空当前行）。所以当最后一行是这些特殊字符时，需要往前再读2个字符来判断是否读到结尾
            if (lastChar_1 == (byte) 75 && lastChar_2 == (byte) 91) {
                if (length >= 5) {
                    if (bytes[length - 3] == (byte) 27) {
                        lastChar_2 = bytes[length - 5];
                        lastChar_1 = bytes[length - 4];
                    }
                }
            }

            if (this.isConnect && this.sshConfig.isJumpServer()) {
                // 如果是连接且是JumpServer连接请求，判断 >+空格 认为已经读入结束了
                if ((lastChar_1 == (byte) ' ') && (lastChar_2 == (byte) this.sshConfig.getJumpServerPrompt())) {
                    return true;
                }
            } else {
                // 如果是执行linux命令，linux认为读到 #+空格 或 $+空格 认为已经读入结束了，如果是 mac 判断 % #
                if ((lastChar_1 == (byte) ' ') && (lastChar_2 == (byte) this.sshConfig.getUserPrompt()) || (lastChar_2 == (byte) this.sshConfig.getRootPrompt())) {
                    return true;
                }
            }
        }
        return false;
    }

}
